#pragma once
#include "SimpleCriticalSection.h"

namespace RoomFW {

/// A Simple (TCP) SOCKET wrapper.
///
///   @author Andrew Sage
class SimpleSocket
{
public:

	/// SimpleSocket smart pointer
	typedef ::boost::shared_ptr<SimpleSocket> SocketPtr;

	/// Array of SimpleSocket smart pointers.
	typedef std::vector<SocketPtr> SocketArray;

	/// Array of indexes
	typedef std::vector<size_t> IndexArray;

	/// Constructor
	SimpleSocket(void);

	/// Destructor
	~SimpleSocket();

	/// Allow implicit cast to contained SOCKET.
	///   @return socket_
	operator SOCKET() const;

	/// Test if SOCKET handle is valid.
	///   @return True if SOCKET handle is valid.
	bool valid(void) const;

	/// Start listening on this socket.
	///     @param port - TCP/IP port to listen on.
	///     @param ipAddress - TCP/IP address to listen on (in dotted number form).
	///   @return Success
    bool listen(unsigned short port, const char* ipAddress);

	/// Accept a new connection.  Must call listen() first.
	///   @return Pointer to connected socket or null on error.
	SocketPtr accept(void);

	/// Connect to a remote address
	///     @param port - TCP/IP port to connect to.
	///     @param ipAddress - TCP/IP address to connect to (in dotted number form).
	///   @return Success
	bool connect(unsigned short port, const char* ipAddress);

	/// Send bytes.  Prefer using sendMessage().
	///     @param buffer - Pointer to bytes to send.
	///     @param size - Number of bytes to send.
	///   @return Success
	bool send(const char* buffer, int size) const;

	/// Send a message (number of bytes followed by bytes).
	///     @param message - Message to send.
	///   @return Success
	bool sendMessage(const std::string& message) const;

	/// Receive bytes.  Prefer using receiveMessage().
	///     @param buffer - Pointer to bytes to receive.
	///     @param size - Number of bytes to receive.  Returns number of bytes not sent.
	///   @return Success.  Returned size > 0 indicates socket closed.
    bool receive(char* buffer, int& size) const;

	/// Receive a message (number of bytes followed by bytes).
	///     @param message - Message to receive.
	///   @return Success.  Returned message empty indicates socket closed.
	bool receiveMessage(std::string& message) const;

	/// Close the SOCKET handle
	///     @param doShutdown - true to shutdown the socket before closing the handle.
	///   @return Success
	bool close(bool doShutdown = true);

	/// Check if a socket is writable.
	///   @return True if the socket is writable, i.e. a call to send shouldn't fail.
	bool isWritable(void) const;

	/// Wait for a socket to be writable.
	///     @param timeout - timeout for wait operation.  Default of null for infinite wait.
	///   @return Success
	bool waitWrite(const timeval* timeout = 0) const;

	/// Check if a socket is readable.
	///   @return True if the socket is readable, i.e. a call to recv shouldn't fail.
	bool isReadable(void) const;

	/// Wait for a socket to be readable.
	///     @param timeout - timeout for wait operation.  Default of null for infinite wait.
	///   @return Success
	bool waitRead(const timeval* timeout = 0) const;

private:

	/// Constructor
	///     @param SOCKET handle.  Takes ownership.
	SimpleSocket(SOCKET socket);

	/// iocltsocket wrapper.
	/// Parameters:	See ::iocltsocket()
	///   @return Success.
	bool ioclt(long cmd, u_long* argp);

	//// CriticalSection guarded winsock ::recv wrapper
	int recv(SOCKET s, char* buf, int len, int flags) const;

	//// CriticalSection guarded winsock ::select wrapper
	int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout) const;

	/// Initialize an internet socket address.  ipAddress in dotted number form.
	static struct sockaddr_in InitializeSockaddr(unsigned short port, const char* ipAddress = 0);

	/// SOCKET handle.
	SOCKET socket_;

	//// Lock to prevent > 1 thread trying to simultaneously ::recv on the same socket.
///	mutable SimpleCriticalSection csRecv_;
///	mutable SimpleCriticalSection csSelect_;
	mutable SimpleCriticalSection cs_;

	/// Listener flag for shutdown.
	bool isListener_;

	/// Not designed to be copied.  SOCKET handle owned by one instance.
	SimpleSocket(const SimpleSocket&);
	SimpleSocket& operator =(const SimpleSocket&);
} ;

}
